//******************************************************************/
//				显示控制模块
//版本说明:
//V0.1		2019-08-01	11:00	yshao	灯饰控制器显示控制
//******************************************************************/
//`define	BOOT_MODE	1
module display_top_lm(
		//复位&时钟
		input	wire		resetb,
		input	wire		sclk,
		
		input	wire	[20:0]	time_us,
		input	wire	[20:0]	sync_us,

		//MCU设置接口
	        input	wire		set_d_ok,
	        input	wire	[31:0]	set_addr,
	        input	wire	[7:0]	set_data,
	        output	wire	[7:0]	set_rd_d,
		
		//端口输入输出
		output	wire		sout,
		
		output	wire		dmx_tx,
		output	wire		dmx_ten,
		output	wire		dmx_flag,
		
		//调试接口
		output	wire	[15:0]	tout
		);

//****************************************************************
//		内部信号
//****************************************************************
//配置参数
reg		dis_cfg_en, d_reverse;
reg	[9:0]	div_count_max, clock_low_time, port_l_unit;
reg	[7:0]	shift_length_per_unit, chip_type;
reg	[15:0]	config_0, config_1, config_2, config_3, config_4, config_5, config_6, config_7;
reg	[7:0]	config_8;
reg	[11:0]	o_l_max, o_l_offset;
reg		o_l_sel_mode;

//电流参数
wire	[7:0]	current_adj1, current_adj2, current_adj3;

//时钟分频
reg	[9:0]	div_cnt;
reg		div_end, out_clk;

//配置缓冲
reg		dis_buf_en, gray_table_en, dis_buf_we, gray_table_we;
reg	[11:0]	dis_buf_waddr, dis_buf_raddr;
reg	[8:0]	gray_table_waddr;
reg	[7:0]	gray_table_raddr;
reg	[7:0]	dis_buf_wdata, gray_table_wdata;
wire	[7:0]	dis_buf_rdata;
wire	[15:0]	gray_table_rdata;

//帧
reg	[7:0]	v_start_mode;
reg	[15:0]	v_start_count;
reg	[5:0]	ms_count;
reg		v_start;

//数据读取
wire		r_start, r_req, r_load, r_shift_r, r_shift_l;
wire	[7:0]	r_c_addr;
wire	[9:0]	r_p_addr;
wire	[3:0]	r_bit_sel;

wire		r_start_1s, r_req_1s, r_load_1s;
wire	[7:0]	r_c_addr_1s;
wire	[9:0]	r_p_addr_1s;
wire	[3:0]	r_bit_sel_1s;

wire		r_start_dmx, r_req_dmx, r_load_dmx;
wire	[7:0]	r_c_addr_dmx;
wire	[9:0]	r_p_addr_dmx;
wire	[3:0]	r_bit_sel_dmx;

reg		r_start_sclk, r_req_a, r_req_b, r_req_sclk;
reg	[3:0]	r_bit_sel_sclk;
reg	[11:0]	r_addr;
reg	[15:0]	pwm_data, s_data;
reg		r_data;

wire	[1:0]	dmx_mode;
wire	[15:0]	out_data_dmx;

/**************************************************************
//			   参数定义
//**************************************************************


//******************************************************************/
//			   内部Sram
//******************************************************************/
//*************显示缓冲*************
swsr_4k8_sdp dis_buf(
	.clkw(sclk),
	.cew(dis_buf_we),
	.aw(dis_buf_waddr),
	.dw(dis_buf_wdata),
	
	.clkr(sclk),
	.cer(1'b1),
	.ar(dis_buf_raddr),
	.qr(dis_buf_rdata)
	);

//*************映射表*************
swsr_512w8_256r16_sdp gray_pwm_table(
	.clkw(sclk),
	.cew(gray_table_we),
	.aw(gray_table_waddr),
	.dw(gray_table_wdata),
	
	.clkr(sclk),
	.cer(1'b1),
	.ar(gray_table_raddr),
	.qr(gray_table_rdata)
	);

//*************显示缓冲写*************
always @(posedge sclk)
	if ((set_addr[31:16] == 16'h0001) && (set_addr[15:12] == 4'h8))
		dis_buf_en <= 1;
	else
		dis_buf_en <= 0;

always @(posedge sclk)
	if (dis_buf_en == 1)
		dis_buf_we <= set_d_ok;
	else
		dis_buf_we <= 0;

always @( * ) begin
	dis_buf_waddr <= set_addr[11:0];
	dis_buf_wdata <= set_data;
	end

//*************映射表写*************
always @(posedge sclk)
	if ((set_addr[31:16] == 16'h0001) && (set_addr[15:12] == 4'h7) && (set_addr[11:9] == 3'h0))
		gray_table_en <= 1;
	else
		gray_table_en <= 0;

always @(posedge sclk)
	if (gray_table_en == 1)
		gray_table_we <= set_d_ok;
	else
		gray_table_we <= 0;

always @( * ) begin
	gray_table_waddr <= set_addr[8:0];
	gray_table_wdata <= set_data;
	end

//******************************************************************/
//			参数控制
//******************************************************************/
//*********************内部寄存器设置***************************/
always @(posedge sclk)
	if (set_addr[31:16] == 16'h0001)
		dis_cfg_en <= 1;
	else
		dis_cfg_en <= 0;
		
always @(posedge sclk or negedge resetb) begin
	if (resetb==0) begin
		div_count_max<= 300;//93((150 / 0.8 / 2) - 1
		clock_low_time<= 150;//30((150 / 0.8 / 2 / 3) - 1
		port_l_unit<=79;
		shift_length_per_unit<=2;
		chip_type<=31; 
	        config_0<= 0;
                config_1<= 0;
                config_2<= 0;
                config_3<= 0;
                config_4<= 0;
                config_5<= 0;
                config_6<= 0;
                config_7<= 0;	
                config_8<= 0;
                d_reverse<=0;
		end
	else if ((set_d_ok == 1) && (dis_cfg_en == 1))
                case (set_addr[15:0])
			16'h3000:div_count_max[6:0]	<=set_data[7:1];
			16'h3001:div_count_max[9:7]	<=set_data;
			16'h3002:clock_low_time[6:0]	<=set_data[7:1];
			16'h3003:clock_low_time[9:7]	<=set_data;
			16'h3004:port_l_unit[7:0]	<=set_data;
			16'h3005:port_l_unit[9:8]	<=set_data[1:0];
		        16'h3006:shift_length_per_unit	<=set_data;
			16'h3008:chip_type	<=set_data;
			16'h300A:d_reverse	<=set_data[0];
			
			16'h3090:config_0[7:0]	<=set_data;
			16'h3091:config_0[15:8]	<=set_data; 
			16'h3092:config_1[7:0]	<=set_data;
			16'h3093:config_1[15:8]	<=set_data; 
			16'h3094:config_2[7:0]	<=set_data;
			16'h3095:config_2[15:8]	<=set_data; 
			16'h3096:config_3[7:0]	<=set_data;
			16'h3097:config_3[15:8]	<=set_data;  
			16'h309a:config_4[7:0]	<=set_data; 
			16'h309b:config_4[15:8]	<=set_data; 
			16'h309d:config_5[7:0]	<=set_data; 	
			16'h309e:config_5[15:8]	<=set_data;	
			16'h309f:config_6[7:0]	<=set_data; 	
			16'h30a0:config_6[15:8]	<=set_data;
			16'h30a1:config_7[7:0]	<=set_data; 	
			16'h30a2:config_7[15:8]	<=set_data;	
			16'h30a3:config_8[7:0]	<=set_data;
		endcase	
	end

assign	current_adj1 = config_5[7:0];
assign	current_adj2 = config_5[15:8];
assign	current_adj3 = config_6[7:0];

//显示数据参数
always@(posedge sclk or negedge resetb)
	if (resetb == 0) begin
		o_l_max <= 512;
		o_l_sel_mode <= 0;
		o_l_offset <= 0;
	end
	else if ((set_d_ok == 1) && (dis_cfg_en == 1))
                case (set_addr[15:0])
			16'hFF00:	o_l_max[7:0] <= set_data;
			16'hFF01:	o_l_max[11:8] <= set_data;
			16'hFF11:	o_l_sel_mode <= set_data[0];
			16'hFF12:	o_l_offset[7:0] <= set_data;
			16'hFF13:	o_l_offset[11:8] <= set_data;
		endcase

//*********************数据返回***************************/
assign	set_rd_d = 0;

//*********************时钟分频***************************/
always @(posedge sclk or negedge resetb)
	if (resetb == 0)
		div_cnt <= 0;
	else if (div_end == 1)
		div_cnt <= 0;
	else
		div_cnt <= div_cnt + 1;

always @(posedge sclk)
	if (div_cnt == div_count_max - 1)
	        div_end <= 1;
	else
		div_end <= 0;

always @(posedge sclk)
	if (div_cnt < clock_low_time)
	        out_clk <= 1;
	else
		out_clk <= 0;

//******************************************************************/
//			   帧控制
//******************************************************************/
//帧模式
always@(posedge sclk or negedge resetb)
	if (resetb == 0)
		v_start_mode <= 0;
	else if ((set_d_ok == 1) && (dis_cfg_en == 1))
                case (set_addr[15:0])
			16'hFF20:	v_start_mode <= set_data;
		endcase

//MCU启动帧发送
always@(posedge sclk or negedge resetb)
	if (resetb == 0)
		v_start_count <= 16'hFFFF;
	else if ((set_d_ok == 1) && (dis_cfg_en == 1) && (set_addr[15:0] == 16'hFF21) && (v_start_mode == 2))
		v_start_count <= 0;
	else if (v_start_count[15] == 0)
		v_start_count <= v_start_count + 1;

//本地帧周期计数
always @(posedge sclk)
	if (v_start_mode != 3)
		ms_count <= 0;
	else if (sync_us[10] == 1) begin
		if (ms_count == 32)
			ms_count <= 0;
		else
			ms_count <= ms_count + 1;
		end

//帧信号
always @(posedge sclk)
	if ((v_start_mode == 3) && (ms_count == 2))
		v_start <= 1;
	else if ((v_start_mode == 2) && (v_start_count[15] == 0))
		v_start <= 1;
	else
		v_start <= 0;

//******************************************************************/
//			   数据读取
//******************************************************************/
//*************读地址*************
always @(posedge sclk) begin
	r_start_sclk <= r_start;
	r_req_a <= r_req;
	r_req_b <= r_req_a;
	r_bit_sel_sclk <= r_bit_sel;
	end
	
always @(posedge sclk)
	if ((r_req_a == 1) && (r_req_b == 0))
		r_req_sclk <= 1;
	else
		r_req_sclk <= 0;

always @(posedge sclk)
	if (r_req_sclk == 1) begin
		if (r_start_sclk == 1)
			r_addr <= o_l_offset;
		else if ((r_addr == o_l_max) && (o_l_sel_mode == 0))
			r_addr <= 0;
		else 
			r_addr <= r_addr + 1;
		end

always @( * )
	dis_buf_raddr <= r_addr;

always @(posedge sclk)
	gray_table_raddr <= dis_buf_rdata;

/*
reg	[15:0]	ttt;

always @(posedge sclk)
	ttt <= gray_table_raddr;

always @(posedge sclk)
	if (r_addr > o_l_max)
		pwm_data <= 0;
	else
		pwm_data <= ttt;
*/

always @(posedge sclk)
	if (r_addr > o_l_max)
		pwm_data <= 0;
	else
		pwm_data <= gray_table_rdata;

//*************读数据*************
always @(posedge out_clk)
	if (r_load == 1)
		s_data <= pwm_data;
	else if (r_shift_r == 1)
		s_data <= {1'b0, s_data[15:1]};
	else
		s_data <= {1'b0, s_data[14:0], 1'b0};
	
always @(posedge sclk)
	r_data = s_data[r_bit_sel_sclk];

//**************************************************************
//		       	灯具控制
//************************************************************** 
//单线控制模块
out_ctrl_GW620x out_ctrl_1(
        .resetb                 (resetb),
        .oclk                   (sclk),
        .out_clk                (out_clk),          
        
	.t_us                   (time_us[0]),
	.t_ms                   (time_us[10]),
	.t_s                    (time_us[20]),
	
        .out_en                 (1'b1),
        .vsin                   (v_start),
        .vsout                  (),
                
        .chip_type              (chip_type),
	.div_count_max		(div_count_max),
        .clock_low_time         (clock_low_time),
        .div_cnt                (div_cnt),
        .port_l_unit            (port_l_unit),
        .shift_length_per_unit  (shift_length_per_unit),
        .current_adj1           (current_adj1),
        .current_adj2           (current_adj2),
        .current_adj3           (current_adj3),
        
        .read_pixel_first       (r_start_1s),
        .read_pixel_req         (r_req_1s),
        .read_pixel_addr        (r_c_addr_1s),
        .read_unit_addr         (r_p_addr_1s),
        .data_load_req          (r_load_1s),
        .data_shift_req         (r_shift_l),
        .data_bit_sel           (r_bit_sel_1s),
        .data_bit               ({14'h0, r_data}),
	
	.out_sync		(),
        .out_data               (sout),
        .clk_out                (),
        .out_data_n             (),
        .clk_out_n              (),
        
        .tout			()
        );

//DMX控制模块
out_ctrl_DMX512 out_ctrl_15(
        .resetb                 (resetb),
        .sclk                   (sclk),
        .out_clk                (out_clk),          
        
	.t_us                   (time_us[0]),
	.t_ms                   (time_us[10]),
	.t_s                    (time_us[20]),
	
        .out_en                 (1'b1),
        .vsin                   (v_start),
        .vsout                  (),

	.state_2		(8'h00),
 	
        .chip_type              (chip_type),
	.div_count_max		(div_count_max),
        .clock_low_time         (clock_low_time),
        .div_cnt                (div_cnt),
        .port_l_unit            (port_l_unit),
        .shift_length_per_unit  (shift_length_per_unit),
        .config_d               (16'h0000),
        .config_custom		(config_8),
                                           
        .read_pixel_first       (r_start_dmx),
        .read_pixel_req         (r_req_dmx),
        .read_pixel_addr        (r_c_addr_dmx),
        .read_unit_addr         (r_p_addr_dmx),
        .data_load_req          (r_load_dmx),
        .data_shift_req         (),
        .data_bit_sel           (r_bit_sel_dmx),
        .r_shift_req		(r_shift_r),
        .data_bit               ({14'h0, r_data}),

 	//DMX输出信号
	.dmx_mode		(dmx_mode),
        .dmx_send_flag		(dmx_flag),
        .out_data_dmx		(out_data_dmx),

 	//DMXACK5034模式标志
        .custom_map		(),
        
	//调试信号
        .tout			()
        );

assign	r_start = r_start_1s | r_start_dmx;
assign	r_req = r_req_1s | r_req_dmx;
assign	r_load = r_load_1s | r_load_dmx;
assign	r_c_addr = r_c_addr_1s | r_c_addr_dmx;
assign	r_p_addr = r_p_addr_1s | r_p_addr_dmx;
assign	r_bit_sel = r_bit_sel_1s | r_bit_sel_dmx;
/*
assign	r_start = r_start_dmx;
assign	r_req = r_req_dmx;
assign	r_load = r_load_dmx;
assign	r_c_addr = r_c_addr_dmx;
assign	r_p_addr = r_p_addr_dmx;
assign	r_bit_sel = r_bit_sel_dmx;
*/
assign	dmx_tx = out_data_dmx[0];
assign	dmx_ten = dmx_mode[0];

//************************************************************/
//		调试接口
//************************************************************/
/*
reg	[63:0]	sss;
reg		sync_sss;

always @(posedge sclk)
	if (sync_us[15] == 1) begin
		sss[15:0] <= div_count_max;
		sss[31:16] <= clock_low_time;
		sss[47:32] <= port_l_unit;
		sss[63:48] <= {v_start_mode, shift_length_per_unit};
//		sss[79:64] <= o_l_max;
//		sss[95:80] <= o_l_offset;
//		sss[111:96] <= {v_start_mode, 7'h00, o_l_sel_mode};
		end
	else if (sync_us[1] == 1)
		sss <= sss[63:1];

always @(posedge sclk)
	if (time_us[15:8] == 0)
		sync_sss <= 0;
	else
		sync_sss <= 1;

assign	tout = {sync_sss, sss[0], time_us[0] | sync_sss};
*/

//assign	tout = {out_clk, v_start};
//assign	tout = {dis_buf_rdata[0], r_addr[0], r_data, dis_buf_waddr[0], dis_buf_we};
assign	tout = {dis_buf_wdata[2:0], dis_buf_waddr[2:0], dis_buf_we, dis_buf_en};

endmodule